<?php
class MySQLReback
{
    private $config;
    private $content;
	private $filename;
	private $linkid;
    private $dbName = array();
    const DIR_SEP = DIRECTORY_SEPARATOR;
    public function __construct($config)
    {
        $this->config = $config;
        header('Content-type: text/html;charset=utf-8');
        $this->connect();
    }
    private function connect()
    {
		$this->linkid = mysql_connect($this->config['host'] .':' . $this->config['port'], $this->config['userName'], $this->config['userPassword']);
        if ($this->linkid) {
            mysql_query("SET NAMES UTF8",$this->linkid);
            mysql_query('set interactive_timeout=24*3600',$this->linkid);
        } else {
            $this->throwException('无法连接到数据库 !');
        }
    }
    public function setDBName($dbName ='*')
    {
        if ($dbName =='*') {
            $rs = mysql_list_dbs();
            $rows = mysql_num_rows($rs);
            if ($rows) {
                for ($i = 0; $i < $rows; $i++) {
                    $dbName = mysql_tablename($rs, $i);
                    $block = array('information_schema','mysql');
                    if (!in_array($dbName, $block)) {
                        $this->dbName[] = $dbName;
                    }
                }
            } else {
                $this->throwException('没有任何数据库 !');
            }
        } else {
            $this->dbName = func_get_args();
        }
    }
    private function getFile($fileName)
    {
        $this->content ='';
        $fileName = $this->trimPath($this->config['path'] . self::DIR_SEP . $fileName);
        if (is_file($fileName)) {
            $ext = strrchr($fileName,'.');
            if ($ext =='.sql') {
                $this->content = file_get_contents($fileName);
            } elseif ($ext =='.gz') {
                $this->content = implode('', gzfile($fileName));
            } else {
                $this->throwException('无法识别的文件格式 !');
            }
        } else {
            $this->throwException('文件不存在 !');
        }
    }
    private function setFile()
    {
        $recognize ='';
        $recognize = implode('_', $this->dbName);
        $fileName = $this->trimPath($this->config['path'] . self::DIR_SEP . $this->filename.'.sql');
        $path = $this->setPath($fileName);
        if ($path !== true) {
            $this->throwException("无法创建备份目录目录'{$path}'");
        }
        if ($this->config['isCompress'] == 0) {
            if (!file_put_contents($fileName, $this->content, LOCK_EX)) {
                $this->throwException('写入文件失败,请检查磁盘空间或者权限 !');
            }
        } else {
            if (function_exists('gzwrite')) {
                $fileName .='.gz';
                if ($gz = gzopen($fileName,'wb')) {
                    gzwrite($gz, $this->content);
                    gzclose($gz);
                } else {
                    $this->throwException('写入文件失败,请检查磁盘空间或者权限 !');
                }
            } else {
                $this->throwException('没有开启gzip扩展 !');
            }
        }
        if ($this->config['isDownload']) {
            $this->downloadFile($fileName);
        }
    }
    private function trimPath($path)
    {
        return str_replace(array('/','\\','//','\\\\'), self::DIR_SEP, $path);
    }
    private function setPath($fileName)
    {
        $dirs = explode(self::DIR_SEP, dirname($fileName));
        $tmp ='';
        foreach ($dirs as $dir) {
            $tmp .= $dir . self::DIR_SEP;
            
        }
		if (!file_exists($tmp) && !@mkdir($tmp, 511)) {
            return $tmp;
        }
        return true;
    }
    private function downloadFile($fileName)
    {
        ob_end_clean();
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Length:' . filesize($fileName));
        header('Content-Disposition: attachment; filename=' . basename($fileName));
        readfile($fileName);
    }
    private function backquote($str)
    {
        return "`{$str}`";
    }
    private function getTables($dbName)
    {
        @($rs = mysql_list_tables($dbName));
        $rows = mysql_num_rows($rs);
        $dbprefix = $this->config['dbprefix'];
        for ($i = 0; $i < $rows; $i++) {
            $tbName = mysql_tablename($rs, $i);
            if (substr($tbName, 0, strlen($dbprefix)) == $dbprefix) {
                $tables[] = $tbName;
            }
        }
        return $tables;
    }
    private function chunkArrayByByte($array, $byte = 5120)
    {
        $i = 0;
        $sum = 0;
        foreach ($array as $v) {
            $sum += strlen($v);
            if ($sum < $byte) {
                $return[$i][] = $v;
            } elseif ($sum == $byte) {
                $return[++$i][] = $v;
                $sum = 0;
            } else {
                $return[++$i][] = $v;
                $i++;
                $sum = 0;
            }
        }
        return $return;
    }
    public function backup($type = 'all', $tableindex = 0, $page = 0, $pagesize = 2000, $time)
    {
		if($pagesize == 0){$pagesize = 1000;}
		$db = M();
		
        $this->content ='/* This file is created by MySQLReback' . date('Y-m-d H:i:s') .' */';
        foreach ($this->dbName as $dbName) {
            $qDbName = $this->backquote($dbName);
            $rs = mysql_query("SHOW CREATE DATABASE {$qDbName}");
            if ($row = mysql_fetch_row($rs)) {
                mysql_select_db($dbName);
                $tables = $this->getTables($dbName);
				if(count($tables) == $tableindex + 1){return true;}
				$table = $tables[$tableindex];
				
				
                //foreach ($tables as $table) {
					$fieldlist = array();
					$fieldlist = $db -> table($table) -> getDbFields();
                    $table = $this->backquote($table);
                    $tableRs = mysql_query("SHOW CREATE TABLE {$table}");
                    if ($tableRow = mysql_fetch_row($tableRs)) {
						
						if(($type == 'structure' || $type == 'all') && ($page == 0)){
							$this->content .= "\r\n /* 创建表结构 {$table} */";
							$this->content .= "\r\n DROP TABLE IF EXISTS {$table};/* MySQLReback Separation */ {$tableRow[1]};/* MySQLReback Separation */";
							$this->filename = $type.'_'.date('Y-m-d_His', $time).self::DIR_SEP.''.$tables[$tableindex];
							$this->setFile();
							$this->content = '/* This file is created by MySQLReback' . date('Y-m-d H:i:s') .' */';
							if($type == 'structure'){
								$next['tableindex'] = $tableindex + 1;
								$next['page'] = 0;
								$next['pagesize'] = $pagesize;
								return $next;
							}
						}
						if($type == 'data' || $type == 'all'){
							$this->filename = $type.'_'.date('Y-m-d_His', $time).self::DIR_SEP.$tables[$tableindex].'_'.$page;
							$tableDateRs = mysql_query("SELECT `".implode('`,`', $fieldlist)."` FROM {$table} limit ".($page*$pagesize).",{$pagesize};",$this->linkid);
							$valuesArr = array();
							$values =''; 
							$count = 0;
							while ($tableDateRow = mysql_fetch_array($tableDateRs, MYSQL_ASSOC)) {
								$count ++;
								foreach ($tableDateRow as &$v) {
									$v ='\'' . addslashes($v) .'\'';
								}
								$valuesArr[] ='(' . implode(',', $tableDateRow) .')';
							}
							if($count == 0){
								$next['tableindex'] = $tableindex + 1;
								$next['page'] = 0;
								$next['pagesize'] = $pagesize;
								return $next;
							}
							$temp = $this->chunkArrayByByte($valuesArr);
							if (is_array($temp)) {
								foreach ($temp as $v) {
									$values = implode(',', $v) .';/* MySQLReback Separation */';
									if ($values !=';/* MySQLReback Separation */') {
										$this->content .= "\r\n /* 插入数据 {$table} */";
										$this->content .= "\r\n INSERT INTO {$table}(`".implode('`,`', $fieldlist)."`) VALUES {$values}";
									}
								}
							}
						}
                    }
                //}
            } else {
                $this->throwException('未能找到数据库!');
            }
        }
        if (!empty($this->content)) {
            $this->setFile();
        }
        $next['tableindex'] = $tableindex;
		$next['page'] = $page+1;
		$next['pagesize'] = $pagesize;
		return $next;
    }
	
	
	
	
	
	
	
	
	
	
	
	public function sitebackup($siteid = 0, $tositeid = 0, $tableindex = 0, $page = 0, $pagesize = 2000, $time=0)
    {
		if($pagesize == 0){$pagesize = 1000;}
		$db = M();
        $this->content ='/* This file is created by MySQLReback' . date('Y-m-d H:i:s') .' */';
		
		
		
		
		
		if($tableindex == 0 && $page == 0){
			$sitedata = $db -> table(C('DB_PREFIX').'site') -> where(array('id' => $siteid)) -> find();
			$setsitedata = array();
			foreach($sitedata as $k => $v){
				if($k == 'id'){continue;}
				
				
				if($v === NULL){
					$setsitedata[] = "`".$k."` = NULL";
				}else{
					$setsitedata[] ='`'.$k.'`=\'' . addslashes($v) .'\'';
				}
				
				
			}
			//没有目标站点时使用插入方法打包
			
		    $updateSiteSql = 'update `'.C('DB_PREFIX').'site` set '.implode(',', $setsitedata).' where id = '.($tositeid > 0 ? $tositeid : '#tositeid#').';/* MySQLReback Separation */';
			$this->filename = $siteid.'_to_'.$tositeid.'_'.date('Y-m-d_His', $time).self::DIR_SEP.'0';
			$this->content .= $updateSiteSql;
			$this->setFile();
			$this->content ='/* This file is created by MySQLReback' . date('Y-m-d H:i:s') .' */';
		}
		
        foreach ($this->dbName as $dbName) {
            $qDbName = $this->backquote($dbName);
            $rs = mysql_query("SHOW CREATE DATABASE {$qDbName}");
            if ($row = mysql_fetch_row($rs)) {
                mysql_select_db($dbName);
                $tables = $this->getTables($dbName); 
				
				
				if(count($tables) == $tableindex + 1){return true;}
				$table = $tables[$tableindex];
				
				
				
				$this->filename = $siteid.'_to_'.$tositeid.'_'.date('Y-m-d_His', $time).self::DIR_SEP.$table.'_'.$page;
				
				
                //foreach ($tables as $table) {
					$fieldlist = $db -> table($table) -> getDbFields();
					
					
					
					
					if(!in_array('site_id', $fieldlist) || C('DB_PREFIX').'member_member' == $table){
						$next['tableindex'] = $tableindex + 1;
						$next['page'] = 0;
						$next['pagesize'] = $pagesize;
						return $next;
					}
					foreach($fieldlist as $fieldkey => $fieldname){
						$fieldlist[$fieldkey] = '`'.$fieldname.'`';
						if($fieldname == 'id'){
							unset($fieldlist[$fieldkey]);
						}
						if($fieldname == 'oldid'){
							unset($fieldlist[$fieldkey]);
						}
		
					}
					 //exit;
                    $table = $this->backquote($table);
                    $tableRs = mysql_query("SHOW CREATE TABLE {$table}");
                    if ($tableRow = mysql_fetch_row($tableRs)) {
                        
						
                        
                            $tableDateRs = mysql_query("SELECT ".implode(',', $fieldlist).",`id` as `oldid` FROM {$table} where site_id = '".$siteid."' limit ".($page*$pagesize).",{$pagesize};", $this->linkid);
							$fieldlist[] = "`oldid`";
					
							
						//
                        $valuesArr = array();
                        $values ='';
						
						
						$count = 0;
						
						//
						
                        while ($tableDateRow = mysql_fetch_array($tableDateRs,MYSQL_ASSOC)) {
							$count ++;
                            foreach ($tableDateRow as $k => &$v) {
								
								
								
								
								//dump($fieldlist);
								//dump($tableDateRow );continue;
								if($k == 'site_id'){
									if($tositeid == 0){
										$v ='#tositeid#';
									}else{
										$v ='\'' . addslashes($tositeid) .'\'';
									}
									
								}else{
									if($v === NULL){
									    $v ='NULL';
									}else{
										$v ='\'' . addslashes($v) .'\'';
									}
								}
                                
								
                            }
                            $valuesArr[] ='(' . implode(',', $tableDateRow) .')';
							
                        }
						
						
						if($count == 0){
							$next['tableindex'] = $tableindex + 1;
							$next['page'] = 0;
							$next['pagesize'] = $pagesize;
							return $next;
						}
						
                        $temp = $this->chunkArrayByByte($valuesArr);
                        if (is_array($temp)) {
                            foreach ($temp as $v) {
                                $values = implode(',', $v) .';/* MySQLReback Separation */';
                                if ($values !=';/* MySQLReback Separation */') {
									
                                    $this->content .= "\r\n /* 插入数据 {$table} */";
                                    $this->content .= "\r\n INSERT INTO {$table}(".implode(',', $fieldlist).") VALUES {$values}";
                                }
                            }
                        } 
                    }
                //} 
            } else {
                $this->throwException('未能找到数据库!');
            }
        }
        if (!empty($this->content)) {
            $this->setFile();
        }
        $next['tableindex'] = $tableindex;
		$next['page'] = $page+1;
		$next['pagesize'] = $pagesize;
		return $next;
    }
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
    public function recover($fileName, $tableindex = 2)
    {
		
		$filetype = explode('_', $fileName);
		if($filetype[1] == 'to' && $filetype[2] == 0 && $tableindex == 2){
			$cursiteid = M('Site') -> add(array ( 'domain' => '', 'name' => NULL, 'img_url' => NULL, 'title' => '新建站点', 'remark' => '', 'uid' => '2', 'timeout' => '0', 'config' => NULL, 'status' => '1', 'template_id' => '44', 'relate_id' => '0', 'is_free' => '1', 'create_time' => '1458636707', 'mapX' => NULL, 'mapY' => NULL));
			session('siteid', $cursiteid);
			session('cur_site_id', $cursiteid);
		}
		$db = M();
		$this->config['path'] = $this->config['path']. self::DIR_SEP . $fileName;
		$files = MyScandir($this->config['path']);
		if(count($files) == $tableindex || count($files) == 2){return true;}
		echo $files[$tableindex];
		if($tableindex == 2){
		$tables = $this->getTables($this->dbName[0]);
		foreach($tables as $table){
			if($filetype[0] == 'all' || $filetype[0] == 'structure'){
				$db -> query('drop table `'.$table.'`;');
			}
			if($filetype[0] == 'data'){
				$db -> query('TRUNCATE `'.$table.'`;');
			}
		}
		}
		
        $this->getFile($files[$tableindex]);
        if (!empty($this->content)) {
			
            $content = explode(';/* MySQLReback Separation */', $this->content);
            foreach ($content as $i => $sql) {
				if($filetype[1] == 'to' && $filetype[2] == 0){
					$sql = str_replace('#tositeid#', session('cur_site_id'), $sql);
				}
				//echo $sql;
                $sql = trim($sql);
                if (!empty($sql)) {
                    $dbName = $this->dbName[0];
                    if (!mysql_select_db($dbName,$this->linkid)) { 
                        $this->throwException('不存在的数据库!' . mysql_error());
                    }
                    $rs = mysql_query($sql,$this->linkid);
                    if ($rs) {
                        if (strstr($sql,'CREATE DATABASE')) {
                            $dbNameArr = sscanf($sql,'CREATE DATABASE %s');
                            $dbName = trim($dbNameArr[0],'`');
                            mysql_select_db($dbName);
                        }
                    } else {
                        $this->throwException($files[$tableindex].'备份文件被损坏!' . mysql_error());
                    }
                }
            }
        } else {
            $this->throwException('无法读取备份文件!');
        }
        return $tableindex + 1;
    }
    private function throwException($error)
    {
        throw new Exception($error);
    }
}